using System;
using System.Collections.Generic;
using SCG.SolarVengeanceEngine;
using SCG.SolarVengeanceEngine.StarShips;
using SCG.General;

namespace SCG.SolarVengeance.Scenarios
{
    public class BeamShipWars : Scenario
    {
        #region Initializations

        private ScenarioParameter enbBH;
        private ScenarioParameter enbPL;
        private ScenarioParameter enbWH;
        private ScenarioParameter enbNE;
        private List<StarShip> vShip = new List<StarShip>();
        private Dictionary<Player, int> oShip = new Dictionary<Player, int>();
        private Dictionary<Player, int> ISDelay = new Dictionary<Player, int>();
        private Dictionary<Player, int> BSDelay = new Dictionary<Player, int>();
        private Dictionary<Player, int> MSDelay = new Dictionary<Player, int>();
        private Dictionary<Player, int> KStreak = new Dictionary<Player, int>();
        private Dictionary<Player, int> StarsOwned = new Dictionary<Player, int>();       
        private string _message = "";
        private string _lastmessage = "";
        private int messagecount = 0;
        private int countdown = 120;

        public BeamShipWars()
        {
            enbBH = CreateParameter("Black Holes Enabled?", 1, 0, 1);
            enbPL = CreateParameter("Pulsars Enabled?", 1, 0, 1);
            enbWH = CreateParameter("Worm Holes Enabled?", 1, 0, 1);
            enbNE = CreateParameter("Nebula Enabled?", 1, 0, 1);
        }

        public override PlayModeRecommendation Recommendation
        {
            get
            {
                return PlayModeRecommendation.MultiPlayer;
            }
        }

        public override string Description
        {
            get { return "This isolated part of the Milky Way Galaxy is proven grounds for BeamShip Tournaments and Contests. "+
                         "Any Star Lord that competes would have to bring the best fleet management skills in order to win. The Star Lord "+
                         "who takes over all the Stellar Points in the cluster for 100 impulses will win. This Scenario is very dangerous because the " +
                         "Black Holes are everywhere! You will never know where they are! Alliances are not supported in this Scenario." + Environment.NewLine + Environment.NewLine +
                         "If you can get 5 kills with a BeamShip without losing all of your BeamShips, you get TechShips." + Environment.NewLine +
                         "Get 10 kills and you get a SpyShip."+ Environment.NewLine +
                         "Get 25 kills and you get a fleet of ParalyShips!" + Environment.NewLine +
                         "Get 50 kills and you get more CLOAKED BeamShips!" + Environment.NewLine +
                         "Get 100 kills and you get a large fleet of HUGE CLOAKED WARSHIPS!." + Environment.NewLine + Environment.NewLine +
                         "If you happen to lose your Inkspots, BattleStation, or BeamShip, they will be automatically recreated, but with a 30 impulse delay.";
            }
        }
        public override string Author
        {
            get { return "Beat2k";
            }
        }

        //don't assign capitals
        public override bool AssignCapitals
        {
            get { return false;
            }
        }

        public override void ClientInitialize()
        {
            countdown = 100;
            vShip.Clear();
            oShip.Clear();
            ISDelay.Clear();
            MSDelay.Clear();
            BSDelay.Clear();
            KStreak.Clear();
            StarsOwned.Clear();
            foreach (Player p in Game.Players)
            {
                ISDelay.Add(p, 30);
                MSDelay.Add(p, 30);
                BSDelay.Add(p, 30);
                KStreak.Add(p, 0);
                StarsOwned.Add(p, 0);
            }
        }

        #endregion

        public override void BuildScenario(int numPlayers, int capitalValues, int startingResources)
        {
            #region BeamShip Fleet Setup

            //clear previously assigned dictionaries
            countdown = 100;
            vShip.Clear();
            oShip.Clear();
            ISDelay.Clear();
            MSDelay.Clear();
            BSDelay.Clear();
            KStreak.Clear();
            StarsOwned.Clear();
            foreach (Player p in Game.Players)
            {
                ISDelay.Add(p, 30);
                MSDelay.Add(p, 30);
                BSDelay.Add(p, 30);
                KStreak.Add(p, 0);
                StarsOwned.Add(p, 0);
            }

            //Determine fleet values for each player, they all share equal strengths
            int stRange = Random(8, 12);
            int scanRange = Random(stRange - 1, stRange + 1);

            //Assign fleet locations of each player, make sure they are not too close to each other, and outside nebula
            List<SCGPoint> pts = new List<SCGPoint>();
            foreach (Player p in Game.Players)
            {
                SCGPoint testPoint = new SCGPoint();
                bool pointOK = false;
                oShip.Add(p, 0);
                while (pointOK == false)
                {
                    //get a random point about 40 spaces away from center
                    testPoint.X = Random(0, 99);
                    testPoint.Y = Random(0, 99);
                    double dist = Distance(testPoint.X, testPoint.Y, 50, 50);
                    if (dist > 35 && dist < 45)
                    {
                        pointOK = true;

                        //must also be at least 20 away from all other players
                        foreach (SCGPoint ptTest in pts)
                            if (Distance(testPoint.X, testPoint.Y, ptTest.X, ptTest.Y) < 18)
                            {
                                pointOK = false;
                                break;
                            }
                    }
                }
               
                //this is the fleet location!
                pts.Add(testPoint);

                //center Battlestation at this location
                int x = (int)testPoint.X;
                int y = (int)testPoint.Y;
                CreateStarShip(x, y, p, StarShipType.BattleStation, 6, 20, false);
                
                //create scanship
                  CreateStarShip(x, y, p, StarShipType.ScanShip, 20, scanRange, false);

                //Create Inkspots
                  for (int d = 0; d < 6; d++)
                      CreateStarShip(x, y, p, StarShipType.InkSpot, 20, 0, false);

                //create BeamShip
                  CreateStarShip(x, y, p, StarShipType.BeamShip, 20, stRange, false);
            }
            #endregion

            #region Create Map


            //Create Random Nebula
            int numNebula = SVGame.RNG.Next(4) + 2;
            while ((numNebula > 0) & (enbNE.Value == 1))
            {
                CreateNebula(SVGame.RNG.Next(80) + 10, SVGame.RNG.Next(80) + 10, SVGame.RNG.Next(3) + 2, SVGame.RNG.Next(100) + 50);
                numNebula--;
            }
            //Create Random Wormholes
            int numWormholes = SVGame.RNG.Next(9) + 2;
            while ((numWormholes > 0) & (enbWH.Value == 1))
            {
                CreateWormhole(SVGame.RNG.Next(100), SVGame.RNG.Next(100), SVGame.RNG.Next(80) + 10, SVGame.RNG.Next(80) + 10);
                numWormholes--;
            }
            //Create Random Pulsars within the cluster
            int pulsars = Random(numPlayers, (numPlayers + 3));
            while (pulsars > 0 && enbPL.Value == 1)
            {
                SCGPoint ptPulsar = new SCGPoint();
                ptPulsar = new SCGPoint(Random(10, 90), Random(10, 90));
                CreatePulsar((int)ptPulsar.X, (int)ptPulsar.Y);
                pulsars--;
            }

            //Create Black Holes just outside the cluster perimeter
            List<SCGPoint> BHPos = new List<SCGPoint>();
            int BlackHoles = Random(numPlayers, (numPlayers + 10));
            while (BlackHoles > 0 && enbBH.Value == 1)
            {
                bool BlackHolesOK = false;
                SCGPoint ptBlackHoles = new SCGPoint();
                while (BlackHolesOK == false)
                {
                    ptBlackHoles = new SCGPoint(Random(1, 98), Random(1, 98));
                    BlackHolesOK = true;
                    //place away from other blackholes
                    if (BlackHolesOK == true)
                    {
                        for (int d = 0; d < BHPos.Count; d++)
                        {
                           double bhdist = Distance(ptBlackHoles.X, ptBlackHoles.Y, BHPos[d].X, BHPos[d].Y);
                           if (bhdist <= 8)
                               BlackHolesOK = false;
                        }
                    }
                    //black holes must be at least 10 away from any fleet
                    if (BlackHolesOK == true)
                    {
                        for (int d = 0; d < pts.Count; d++)
                        {
                            double bhdist = Distance(ptBlackHoles.X, ptBlackHoles.Y, pts[d].X, pts[d].Y);
                            if (bhdist <= 10)
                                BlackHolesOK = false;
                        }
                    }
                }

                CreateBlackHole((int)ptBlackHoles.X, (int)ptBlackHoles.Y, Random(10, 15));
                BHPos.Add(ptBlackHoles);
                BlackHoles--;
            }

            //Create Stellar Points (Stars) will be located away from black holes
            for (int d = 0; d < 3 + Game.Players.Count; d++)
            {
                bool stellarpointok = false;
                SCGPoint stpoint = new SCGPoint(50, 50);
                while (stellarpointok == false)
                {
                    stpoint.X = Random(10, 90);
                    stpoint.Y = Random(10, 90);
                    stellarpointok = true;
                    for (int dd = 0; dd < BHPos.Count; dd++)
                    {
                        double bhdist = Distance(stpoint.X, stpoint.Y, BHPos[dd].X, BHPos[dd].Y);
                        if (bhdist <= 10)
                            stellarpointok = false;
                    }
                }

                CreateStarSystem((int)stpoint.X, (int)stpoint.Y, 0, 0, 10, 0);
            }

            #endregion
        }

        //render status labels
        public override void CustomRendering(ISVCustomRenderer renderer)
        {
            renderer.DrawTextScreenCoords(_kills, 8, 8, SCGColor.Red, 12);
            renderer.DrawTextScreenCoords(_owned, 8, 28, SCGColor.Red, 12);
        }

        #region Process Player Information and Victory Conditions

        private string _kills = "";
        private string _owned = "";
        public override void ClientProcessImpulse(int impulse)
        {
            string kstr;
            string sown;
            foreach (Player p in Game.Players)
            {
                kstr = GetValue("KS" + p.Name);
                sown = GetValue("SO" + p.Name);
                if ((kstr == "") | (kstr == null)) kstr = "0";
                if ((sown == "") | (sown == null)) sown = "0";
                if (KStreak.ContainsKey(p) == false)
                    KStreak.Add(p, Int32.Parse(kstr));
                else
                    KStreak[p] = Int32.Parse(kstr);
                if (StarsOwned.ContainsKey(p) == false)
                    StarsOwned.Add(p, Int32.Parse(sown));
                else
                    StarsOwned[p] = Int32.Parse(sown);
            }
            _kills = "Consecutive Kills with Beamship : " + KStreak[Game.CurrentPlayer].ToString();
            _owned = "Stellar Points Owned : " + StarsOwned[Game.CurrentPlayer].ToString() + " / " + Game.StarSystems.Count.ToString();
        }

        public override void ProcessImpulse(int impulse)
        {
            Player vp = null;
            int numplayers = Game.Players.Count;
            int pIS = 0;
            int pBS = 0;
            int pMS = 0;

            string tmp = GetValue("message");
            if ((tmp != "") & (tmp != null))
            {
                _message = tmp;
            }
            if (_lastmessage != _message)
            {
                _lastmessage = _message;
                messagecount = 5;
            }
            else if (messagecount > 0)
            {
                messagecount--;
                DynamicEvents.DisplayMessage(_message);
            }

            #region StarSystem Count and Victory Countdown.

            foreach (Player p in Game.Players)
            {
                StarsOwned[p] = 0;
            }
            foreach (StarSystem sys in Game.StarSystems)
            {
                if (sys.Owner != null)
                {
                    StarsOwned[sys.Owner]++;
                }
            }
            foreach (Player p in Game.Players)
            {
                if (StarsOwned[p] >= Game.StarSystems.Count)
                {
                    countdown--;
                    _message = p.Name + " has control of all points! Time left : " + countdown.ToString();
                    SetValue("message", _message);
                }
                else if (StarsOwned[p] > 0)
                {
                    countdown = 120;
                }
            }
            if (countdown <= 0)
            {
                foreach (Player p in Game.Players)
                {
                    if (StarsOwned[p] <= 0)
                    {
                        p.Eliminated = true;
                    }
                    else
                    {
                        p.Victor = true;
                    }
                }
            }
            #endregion

            #region Starship Count and Respawn.
            SCGPoint ptm = new SCGPoint();
            Dictionary<Player, SCGPoint> BSLocations = new Dictionary<Player, SCGPoint>();
            foreach (Player p in Game.Players)
            {
                oShip[p] = 0;
                pIS = 0;
                pBS = 0;
                pMS = 0;
                if (BSLocations.ContainsKey(p) == false)
                    BSLocations.Add(p, new SCGPoint(50, 50));
                foreach (StarShip s in Game.StarShips)
                {
                    if (s.Owner == p)
                    {
                        oShip[p]++;
                        if (s.ShipType == StarShipType.InkSpot) pIS++;
                        if (s.ShipType == StarShipType.BeamShip) pMS++;
                        if (s.ShipType == StarShipType.BattleStation)
                        {
                            pBS++;
                            BSLocations[p] = s.Location;
                        }
                    }
                }
                if (pIS <= 3)
                {
                    if (ISDelay[p] <= 0)
                    {
                        ISDelay[p] = 30;
                        ptm = GetNewRespawnPoint();
                        for (int d = 0; d < 9; d++)
                            DynamicEvents.CreateStarShip((int)ptm.X, (int)ptm.Y, p, StarShipType.InkSpot, 20, 0, (Random(0, 100) >= 90));
                    }
                    else
                    {
                        ISDelay[p]--;
                    }
                }
                if (pBS <= 0)
                {
                    if (BSDelay[p] <= 0)
                    {
                        BSDelay[p] = 30;
                        ptm = GetNewRespawnPoint();
                        DynamicEvents.CreateStarShip((int)ptm.X, (int)ptm.Y, p, StarShipType.BattleStation, 6, 20, (Random(0, 100) >= 99));
                    }
                    else
                    {
                        BSDelay[p]--;
                    }
                }
                if (pMS <= 0)
                {
                    KStreak[p] = 0;
                    if (MSDelay[p] <= 0)
                    {
                        MSDelay[p] = 30;
                        ptm = GetNewRespawnPoint();
                        DynamicEvents.CreateStarShip((int)ptm.X, (int)ptm.Y, p, StarShipType.BeamShip, 20, 10, (Random(0, 100) >= 99));
                    }
                    else
                    {
                        MSDelay[p]--;
                    }
                }
                if (oShip[p] == 0)
                    p.Eliminated = true;
            }
            #endregion

            #region Beamship Attack Handler.

            //detect beamship orders and confirm kill. give player bonus starships if kill streak is
            List<Player> UpdateKS = new List<Player>();
            foreach (StarShip s in Game.StarShips)
            {
                if (s.ShipType == StarShipType.BeamShip)
                {
                    BeamShip bs = s as BeamShip;
                    if (bs.BeamTarget != null)
                    {
                        UpdateKS.Add(s.Owner);
                    }
                }
            }
            //reason why I did not place this in above loop is that the collection modified exception occurrs..
            for (int m = 0; m < UpdateKS.Count; m++)
            {
                Player p = UpdateKS[m];
                KStreak[p]++;
                if (KStreak[p] == 5)
                {
                    ptm = GetNewRespawnPoint();
                    for (int d = 0; d < 5; d++)
                        DynamicEvents.CreateStarShip((int)ptm.X, (int)ptm.Y, p, StarShipType.TechShip, 3, 0, false);
                }
                if (KStreak[p] == 10)
                {
                    ptm = GetNewRespawnPoint();
                    DynamicEvents.CreateStarShip((int)ptm.X, (int)ptm.Y, p, StarShipType.SpyShip, 20, 20, false);
                }
                if (KStreak[p] == 25)
                {
                    ptm = GetNewRespawnPoint();
                    for (int d = 0; d < Game.StarSystems.Count; d++)
                        DynamicEvents.CreateStarShip((int)ptm.X, (int)ptm.Y, p, StarShipType.ParalyShip, 20, 20, false);
                }
                if (KStreak[p] == 50)
                {
                    ptm = GetNewRespawnPoint();
                    for (int d = 0; d < Game.Players.Count; d++)
                        DynamicEvents.CreateStarShip((int)ptm.X, (int)ptm.Y, p, StarShipType.BeamShip, 20, 20, true);
                }
                if (KStreak[p] == 100)
                {
                    ptm = GetNewRespawnPoint();
                    for (int d = 0; d < Game.StarSystems.Count * 5; d++)
                        DynamicEvents.CreateStarShip((int)ptm.X, (int)ptm.Y, p, StarShipType.WarShip, 20, 100, true);
                }
            }

            #endregion

            #region Last Player Standing Victory.

            //See if there is only player left in the game..
            foreach (Player p in Game.Players)
            {
                if (oShip[p] == 0)
                    numplayers--;
                else
                    vp = p;
            }
            if (numplayers == 1)
            {
                vp.Victor = true;
            }

            #endregion

            foreach (Player p in Game.Players)
            {
                SetValue("SO" + p.Name, StarsOwned[p].ToString());
                SetValue("KS" + p.Name, KStreak[p].ToString());
            }

        }

        private SCGPoint GetNewRespawnPoint()
        {
            SCGPoint ptm = new SCGPoint(Random(5,95),Random(5,95));
            bool pointfound = false;
            while (pointfound == false)
            {
                pointfound = true;
                ptm.X = Random(5, 95);
                ptm.Y = Random(5, 95);
                //place away from blackholes
                for (int d = 0; d < Game.BlackHoles.Count; d++)
                {
                    double bhdist = Distance(ptm.X, ptm.Y, Game.BlackHoles[d].X, Game.BlackHoles[d].Y);
                    if (bhdist <= 10)
                        pointfound = false;
                }
                //and place away from stellar points
                if (pointfound == true)
                {
                    for (int d = 0; d < Game.StarSystems.Count; d++)
                    {
                        double bhdist = Distance(ptm.X, ptm.Y, Game.StarSystems[d].X, Game.StarSystems[d].Y);
                        if (bhdist <= 10)
                            pointfound = false;
                    }
                }
            }
            return ptm;
        }

        #endregion

    }
}




